#include <stdio.h>
#include <stdlib.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

/*This Random Test Will Test the Adventurer Card. The Adventurer Card has a player draw cards
 * until two treasure cards are drawn. The other cards are then discarded */

#define NOISY_TEST 0		//debug mode
#define NUM_TESTS 5000	
#define SEED 1003		//needed to run dominion.c
#define MAX_CARD treasure_map 	//max integer representation of card in dominion.c

typedef struct gameState gameState;

//helper function to initialize game struct to 0's
void clearGameState(struct gameState *G) {
	int i;
	for (i=0; i<sizeof(struct gameState); i++) {
		((char *)G)[i] = 0;
	}
}

int main (int argc, char *argv[]) {

	int i, j, k;
	int currentPlayer, handCount, deckCount, discardCount;	//relevant to refactored adventurer card in dominion.c
	int cur_card = 0;
	int passed_tests = 0;
	int failed_test = 0;
	int treasure_cards_G1 = 0;
	int treasure_cards_G2 = 0;
	int adv_not_discarded = 0;
	int handCount_test, treasure_test, discard_test, played_test = 0;	
	
	//create two gameStates. Our random test works by testing our function on two equivalent gameStates and comparing them
	struct gameState G1, G2;
	
	//initialize random number using rngs.h library
	SelectStream(1);
	PutSeed((long)SEED);
	
	//main test loop
	for (i=0; i < NUM_TESTS; i++) {
	  
	  if (NOISY_TEST) { printf("****************************\nTest number: %d\n", i+1); }
	  failed_test = 0;
	  treasure_cards_G1 = 0;
	  treasure_cards_G2 = 0;
	  adv_not_discarded = 0;
	  
	  //blank each game state
	  clearGameState(&G1);
	  clearGameState(&G2);
	  
	  //get a random # of valid players (2-4), and make it their turn.
	  currentPlayer = (int)(Random()*4);
	  G1.whoseTurn = currentPlayer;
	  G2.whoseTurn = currentPlayer;
	  if (NOISY_TEST) { printf("currentPlayer is: %d\n", currentPlayer); }
	  
	  //get a random handCount, discardCount and deckCount. Run a very high deckcount in the event that it takes a LONG time to get two treasure cards.
	  //make sure we have at least 2 in the hand and discard.
	  handCount = (int)(Random()*10) + 2;
	  if (NOISY_TEST) { printf("handCount is %d\n", handCount); }
	  discardCount = (int)(Random()*10) + 2;
	  if (NOISY_TEST) { printf("discardCount is %d\n", discardCount); }
	  deckCount = (int)(Random()*10) + 200;						//BUG IN DOMINION.C, avoid it by making deckCount very high.
	  if (NOISY_TEST) { printf("deckCount is %d\n", deckCount); }
	  
	  //Create a random hand, deck, and discard pile for our player. Make sure adventurer isn't in the hand early by checking for it.
	  //Hand
	  for (j=0; j < handCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     if (cur_card == adventurer) { cur_card = estate; }				//explicitly set it to an uninteresting card
	     G1.hand[currentPlayer][j] = G2.hand[currentPlayer][j] = cur_card;		//place card in handCount
	  }
	  
	  //Deck
	  for (j=0; j < deckCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     G1.deck[currentPlayer][j] = G2.deck[currentPlayer][j] = cur_card;		//place card in deck
	  }
	  
	  //Discard
	  for (j=0; j < discardCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     G1.discard[currentPlayer][j] = G2.discard[currentPlayer][j] = cur_card;	//place card in discard
	  }
	  
	  //add adventurer card to player's hand. update gameState with our randomly assigned hand, deck, and discard counts.
	  G1.handCount[currentPlayer] = G2.handCount[currentPlayer] = handCount;
	  G1.handCount[currentPlayer]++;
	  G2.handCount[currentPlayer]++;
	  
	  G1.hand[currentPlayer][handCount] = G2.hand[currentPlayer][handCount] = adventurer;
	  G1.deckCount[currentPlayer] = G2.deckCount[currentPlayer] = deckCount;
	  G1.discardCount[currentPlayer] = G2.discardCount[currentPlayer] = discardCount;
	  
	  if (NOISY_TEST) {
	    for (k=0; k < G1.handCount[currentPlayer]; k++) {
	      cur_card = G1.hand[currentPlayer][k];
	      printf("Before Card Effect -- Player %d: Card %d is %d\n", currentPlayer, k, cur_card);
	    }
	  }
	  
	  //Call the cardEffect on only the first gameState.
	  cardEffect(adventurer, 0, 0, 0, &G1, handCount, 0);
	  
	  if (NOISY_TEST) {
	    printf("******************************\n");
	    for (k=0; k < G1.handCount[currentPlayer]; k++) {
	      cur_card = G1.hand[currentPlayer][k];
	      printf("After Card Effect -- Player %d: Card %d is %d\n", currentPlayer, k, cur_card);
	    }
	  }
	  
	  //test that the handCount for currentPlayer is 1 higher (added two treasure cards, discarded adventurer)
	  if (G1.handCount[currentPlayer] != G2.handCount[currentPlayer] + 1) {
	    printf("Test for handCount incrementing by one FAILED: Expected %d cards in hand, have %d\n", G2.handCount[currentPlayer]+1, G1.handCount[currentPlayer]);
	    failed_test = 1;
	  } else {
	    handCount_test++;
	  }
	  
	  //test that the hand has two treasure cards more than it did before. do this by comparing that G1 has two more treasure cards than G2
	  for (k=0; k < G1.handCount[currentPlayer]; k++) {
	    cur_card = G1.hand[currentPlayer][k];
	    if (cur_card == gold || cur_card == silver || cur_card == copper) {
	      treasure_cards_G1++;
	    }
	  }
	  
	  for (k=0; k < G2.handCount[currentPlayer]; k++) {
	    cur_card = G2.hand[currentPlayer][k];
	    if (cur_card == gold || cur_card == silver || cur_card == copper) {
	      treasure_cards_G2++;
	    }
	  }
	  
	  if (treasure_cards_G1 != (treasure_cards_G2 + 2)) {
	      printf("Test for hand having two more treasure cards FAILED: Expected %d cards, hand has %d cards.\n", treasure_cards_G2 + 2, treasure_cards_G1);
	      failed_test = 1;
	  } else {
	      treasure_test++;
	  }
	  
	  //test adventurer card has been discarded from hand
	  for (k=0; k < G1.handCount[currentPlayer]; k++) {
	    cur_card = G1.hand[currentPlayer][k];
	    if (cur_card == adventurer) {
	      printf("Test for discarding adventurer FAILED: The card is in the hand at position %d.\n", k);
	      failed_test = 1;
	      adv_not_discarded = 1;
	    }
	  }
	  if (adv_not_discarded == 0) {discard_test++;}
	  
	  //test adventurer card is in played card pile. testing this way works because it was a blank game state.
	  if (G1.playedCards[G1.playedCardCount - 1] != adventurer) {
	    printf("Test for adventurer in playedCards FAILED: At the top of the playedCard pile is %d\n", G1.playedCards[G1.playedCardCount]);
	    failed_test = 1;
	  } else {
	    played_test++;
	  }
	  
	  //increment a passed_test iteration if all tests succeeded.
	  if (failed_test == 0) {
	    passed_tests++;
	  }
	  
	}
	
	//print the overall result of the tests
	printf("\n************OVERALL TEST RESULTS***********\nOut of %d tests, %d tests completed without any failures\n", NUM_TESTS, passed_tests);
	printf("Out of %d tests, %d tests correctly incremented the handCount by one\n", NUM_TESTS, handCount_test);
	printf("Out of %d tests, %d tests correctly report two additional treasure cards\n", NUM_TESTS, treasure_test);
	printf("Out of %d tests, %d tests correctly discard the adventurer card\n", NUM_TESTS, discard_test);
	printf("Out of %d tests, %d tests correctly place the adventurer card in the playedCards pile\n", NUM_TESTS, played_test);
	
	
	return 0;
}


/* FOR REFERENCE
 * 
 * int new_adventurer(int currentPlayer, int drawntreasure, int cardDrawn, int *temphand, int z, struct gameState *state) {

	while(drawntreasure < 2) {
	
		if (state->deckCount[currentPlayer] < 1) { 		//if the deck is empty we need to shuffle discard and add to deck
			shuffle(currentPlayer, state);
		}
		
		drawCard(currentPlayer, state);
		
		cardDrawn = state->hand[currentPlayer][state->handCount[currentPlayer]];	//top card of hand is most recently drawn card.
		
		if (cardDrawn == copper || cardDrawn == silver || cardDrawn == gold)
		  drawntreasure++;
		  
		else {
		  temphand[z]=cardDrawn;
		  state->handCount[currentPlayer]--; //this should just remove the top card (the most recently drawn one).
		  z++;
		}
	}
	
	while(z-1>=0) {
		state->discard[currentPlayer][state->discardCount[currentPlayer]++]=temphand[z-1]; // discard all cards in play that have been drawn
		z=z-1;
	}

return 0;
}
*/




